package org.bouncycastle.jcacje.provider.test;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;

import javax.crypto.KEM;
import javax.crypto.SecretKey;

import junit.framework.TestCase;
import org.bouncycastle.jcajce.spec.KEMParameterSpec;
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
import org.bouncycastle.pqc.jcajce.spec.NTRUParameterSpec;
import org.bouncycastle.pqc.jcajce.interfaces.NTRUKey;
import org.bouncycastle.util.Arrays;


public class NTRUKEMTest
    extends TestCase
{
    public void setUp()
    {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null)
        {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    // Test for no KDF
//    public void testKEMVec()
//        throws Exception
//    {
//            Security.addProvider(new BouncyCastlePQCProvider());
//
//        // count 0
////        byte[] seed = Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1");
////        byte[] pk = Hex.decode("01031FE0C4328B956E9AFA7B5D86DE2CBF1F0728A1236F685DD2FD221ACDD05CAB64B01AF7A5F3C2837A5B7FE5FE31E366F7F04C5B77C1D6BD3B25A765A84CF9AA08FD9ABA3BB6A4B5C3504064D0803687A04F06B2BB5F7BB95AABF6CB823ACC6E74E98FC468C3E07BCAE284797221A8C8A16168A91A03D066F0EC93F26C8BB6E948BECB9919A72E0FB86F380F1F2C1A2EFCEF871D6ACE4F5E0AD226A80117F7CEEFE566193D872A9ABADB9873D3E9ABB0119CF4133D06F0DA9F0ECB6319CEE796F2FF5B85B4A6754AD4C94346E325BAFF9CC922561CF02B827E2A487ECE6A4AD9ABBDE1D81C218CD5D50A66B8E3EB9870C9F68457BC813A2D827EA7C87951439DD394DA1ED071E8AAEE175BDBFC5CE2ACDE12F78C9B82D9653B970F035A130A1DFBE5B2D4C186C909B9ADF4FB821B2FA21EC03D8D8E095D68F4CC12CEDBE1DE7428A201B04A9575BE758D58340E73602C3467876A4B18218C34A3126DBCC877144E4A42A45005217D9C50F38DBAFAC6477011DA1A1FC749F26B6C747DDADF1F1E4707440A34C22046A6145D3033408212254FBEFAE6A4FCF5AA41BA14EF3C6CA23F3E04CA53A5C2AA03C717A04E928E5DD392ADFBA921528E54944B4183ACBED4D21DFFA3F33D35B9679068B3711AC438F7CAF3042436A9C0BB296ED1C7891B7B782EAABFCE080BDC54CB4EAE3E75536171BF1235397ED37A4394D05D31D7274A1640C1B42912CD9AEBB6B323C370130A854E5BB2253D6F3CA7AFA061C241646C28A8D1EA7AACA73A028920C2BA5DC9EC21F1645B92B35FE810E024CB764CE53F611E61DFC62CEDD8BCD445870D50EBD4DD8021924CC366FADE330AC3826DBF43A328254C367B15718967D72EB4F7EC3BFB692B5BEF357BEF0974739400113F766922F3171964E303D255FE2453BE85AA7B9B9B6408D1655D475BE7EF0351273BC084C9E71B794FAC5C256E87CFEDE5FD8E03EC272B24675B947BB5C1711D894285E026221A152D19DDE65ED293710D195D31968D18E9E2ACF3A0BF5C9F4760B1C20DDCB49FD9A24A3027025A5C090C708E97CD0F273E89DD43180ABEAC4665478732683325406CFBF20BF3059AE57756FAF185612EC199424EC64EC444BC190F0FAA6B2E9A2D96E7814E2FC3BF673B87B7CEC8D6F3A814B5774CF95490E258F0B10269E1ADD8C1D1C4BDD5346ABD921CE3E02A2D051A95E56DFE9A0C655D926FCA45D445170498F6D0870BC8D3F444982E55DE23D59A385E1F18732F7D7F6526289C6659D4363009EBCDF2066411E49E3A8E3D6B312DDCC49169BBF9B13C827A88ACFD5B3E61A9116916F41052A3AAF50ABDA2E7CAA9DB7EA816F44C0F315CB86700F62E25E05C90294FBD55342D62BAFA8BA55BEE7B532D50CD947065E704E625");
////        byte[] sk = Hex.decode("5515559645A956544158655545514489451621815999295514A25949655418096985596A011900615556598565956A6866A916555455214551995455460640548011661525945242549500A515565165659455A52545A6A5445050A2054599A4659591541906682494418654A68A969155864655419119405555105595842994525415591649A569515155058551859A565A8854655454848415444169519555149656009A284AA0664A42991A8809015AA6555A54AA551010460084421102809A028A940502189698410446514812188888644650A081288196648158A61261A94A50908918A5810846011A9925260685A244404A0A585A0289066611A85A5A12408668A6A6591565185058559A18658821104418281602A994A6505012A82A662412A40255690122299A0954295A946110669299104014952500529294624041461249AA142A0201031FE0C4328B956E9AFA7B5D86DE2CBF1F0728A1236F685DD2FD221ACDD05CAB64B01AF7A5F3C2837A5B7FE5FE31E366F7F04C5B77C1D6BD3B25A765A84CF9AA08FD9ABA3BB6A4B5C3504064D0803687A04F06B2BB5F7BB95AABF6CB823ACC6E74E98FC468C3E07BCAE284797221A8C8A16168A91A03D066F0EC93F26C8BB6E948BECB9919A72E0FB86F380F1F2C1A2EFCEF871D6ACE4F5E0AD226A80117F7CEEFE566193D872A9ABADB9873D3E9ABB0119CF4133D06F0DA9F0ECB6319CEE796F2FF5B85B4A6754AD4C94346E325BAFF9CC922561CF02B827E2A487ECE6A4AD9ABBDE1D81C218CD5D50A66B8E3EB9870C9F68457BC813A2D827EA7C87951439DD394DA1ED071E8AAEE175BDBFC5CE2ACDE12F78C9B82D9653B970F035A130A1DFBE5B2D4C186C909B9ADF4FB821B2FA21EC03D8D8E095D68F4CC12CEDBE1DE7428A201B04A9575BE758D58340E73602C3467876A4B18218C34A3126DBCC877144E4A42A45005217D9C50F38DBAFAC6477011DA1A1FC749F26B6C747DDADF1F1E4707440A34C22046A6145D3033408212254FBEFAE6A4FCF5AA41BA14EF3C6CA23F3E04CA53A5C2AA03C717A04E928E5DD392ADFBA921528E54944B4183ACBED4D21DFFA3F33D35B9679068B3711AC438F7CAF3042436A9C0BB296ED1C7891B7B782EAABFCE080BDC54CB4EAE3E75536171BF1235397ED37A4394D05D31D7274A1640C1B42912CD9AEBB6B323C370130A854E5BB2253D6F3CA7AFA061C241646C28A8D1EA7AACA73A028920C2BA5DC9EC21F1645B92B35FE810E024CB764CE53F611E61DFC62CEDD8BCD445870D50EBD4DD8021924CC366FADE330AC3826DBF43A328254C367B15718967D72EB4F7EC3BFB692B5BEF357BEF0974739400113F766922F3171964E303D255FE2453BE85AA7B9B9B6408D1655D475BE7EF0351273BC084C9E71B794FAC5C256E87CFEDE5FD8E03EC272B24675B947BB5C1711D894285E026221A152D19DDE65ED293710D195D31968D18E9E2ACF3A0BF5C9F4760B1C20DDCB49FD9A24A3027025A5C090C708E97CD0F273E89DD43180ABEAC4665478732683325406CFBF20BF3059AE57756FAF185612EC199424EC64EC444BC190F0FAA6B2E9A2D96E7814E2FC3BF673B87B7CEC8D6F3A814B5774CF95490E258F0B10269E1ADD8C1D1C4BDD5346ABD921CE3E02A2D051A95E56DFE9A0C655D926FCA45D445170498F6D0870BC8D3F444982E55DE23D59A385E1F18732F7D7F6526289C6659D4363009EBCDF2066411E49E3A8E3D6B312DDCC49169BBF9B13C827A88ACFD5B3E61A9116916F41052A3AAF50ABDA2E7CAA9DB7EA816F44C0F315CB86700F62E25E05C90294FBD55342D62BAFA8BA55BEE7B532D50CD947065E704E62500D57230D15E762228DA98178A193D7D95284B20E82D74228146FDF68D59B37C5E7F78C0E14E7C40BD4F4D9CF0B189B69983DD39E29AA6439ECAB0A5B294D2A1216CE31CAC6D1B2358D2B0476C4D8002519B6D63639B2D4564E2458C8E06BDEEBE82262570777780F43B110A96547415A69A38EF0ECE0C2AF16B9CF11FF8326E2DE6DD0333B2EDE445AA3A1057824478BFC71FD00DEE601938734810D816F4DADD35F4C152B10CF13957945F8CC47FEF0CE3BDD1F0C5D8CD24B07E3F6D2A5D01717CFD06");
//        byte[] ct = Hex.decode("BC60F537CD5FE3038DACE613B8819A0DC920B8FE092474F763A1BD05F69137A1A084AA1A45A5BF1055F9340368D60CE415217C2C382E7EFFCD289D62A0A9E1E7FA2EFD07EF4B75B02DD436535AED897AECD520763AC7F8DFAFEBC122594388F210DF28DE472E748CFB640E8899B07CB4514401DEF9E9C542DC89733F20F9605F641DD1DD6F332DC051C2E5B2C391ACE70FD00FBC251EE1EA2AB27D165F966DA338F8AA970AAF66931F7CC68E2846EE5AD7EAF8E15B9CA333AD1260163E2BE2324C03094E249D3418164A655BD469E506F5B8420BF4FF6080DA230373B18D74AF03F11C9B545E3791CCC9B3B9927B2222983B7A6DE620BE8520B215ECDA45302695C0229C2A9607260BFD3C6EB9D7EAFAB5E47FD5760FA23067BAC1E6A980C4727B0C187A5B6397AC43D3BE24C42A1D2FCFE43512494A7BFC5CC19455DF6AA6F2698A2903831CA2E5F4F84442E6A74BC9D3CC3D6FBEE97D5CF4B6C58D3DC9ADB359FB56CF35FE21F96E885624498ACDF0BAF3A52B7F2564D1EA384DDA7FD32167786C5E010C3BCF5D2E7164BD6ECE815366887250D184F8061E57C3935214F191B38E982132EF4262E91808FF1CFD902B5248F6E7C031A98234DE0D578D1234B7453F2F575A88B622B0F11902C2146F45912E9BDAFA0846AF7B6789E621ABE3C65A4D990A96488B6307BE210887E82BBADFB026B60CA7DF3C9D429D8FEFCCC93A82E345F3B17756F6341F5DB3151974B1B9C7AC4AA33E80923475FE38FFC0AE7F47529360787AC283008971D87FB07369BAD111F1B99FAA59F2E1B5C088A5F31A47ED6A8E30FF6465A7DC79967EA78891C8EBD462D2566A4EA30EDFB8B7BEDD3C4E2ABFEEE7B366125A19B6372CEE2EB2F85514648AE920D292F444E6F90346DF87FD7C107848796219027BA581B3D87704FA8605108CA88ACF262C5C07D9BFB42635A1944634AF0633B471D0D2B2E4D6284894E0E48D58AE5D07E95130C9FBA77A0F124F9348E1A570BA0D009B7B46E03CEB201B17114B935AA91691A7F830346636FD34ECE2CC295D0124AD8CA76CC81E942C1607699F0DFFD3BDB509392FAF8212363F562554B05F756FF252765E6FCAFB04C6F2CF6A76F2E59E14F5BD4EA8E2ECF50B17E632F346D697FFB7AEB82ADDEF5B4DEC0DEE73D2D96B1A33C6AB4BCF7A160B79114A48F224FA037315ADF0485AB63DC2BF09F02606DAD80F13F0ED0241E6F53B21BBBE584794F77D0B783A7093F53AC916A848FF0F9FA3FB08A053C4");
//        byte[] ss = Hex.decode("2FFCE8C89E97BBA86A7ECD68088FB116A20601B88B8E88A3783CF2D2ED439769");
//
//        byte[] fixedRandomBytes = Hex.decode("7c9935a0912822144249e045d113b6e7cca2aa19b94d210a458e4c8dffc19aa7053095f130f12e7d79262cf801e5f36f63bf9ba079264c836bb02cd0a45a6dee06b7ccda4d18d429cfb5c7784eedcf12e28519d7da3ffcd65731b6d5b773204a55671a9d60940059720a74baa026a7777cd11dd3f81dbf836a06906d60aea820cdb70b606781805857448d6233a8e174b9c5e89cace15b40002c75a3b2c820a2846de5d6bf7c655a9b794d36e4eacbefaebadc20b9b7018c4fb60bb77f17d924db45bfbf74d2d052f8ec84b04cd70f6693f2eac613a0b55d9ad4d951d3808e66cd9d716ed9338a25aa41a9fdad9f7b46f10c6c8338bf52f8b4e2bf25e5e4071beb03e83b558e5db80a224da29951496268ae19980cea3c200e489eeeed9c16e2f0ac2d8daa9822958a84a0ba2fc08d4dba8fe84a3e60acab2183d1e795e74e58ee25a9e6d1fbcb30e564f9628bab26a674f9969d2625b7b7473c29bcc926486d1620bb9e9fcc107f1dded7c80189e7fa361fe8dd996b9c2d8f683847caa95d1542678bd200063bdb5757a4b6a72e8071b246df24fd5b30cf94eedef6ac59c892eebb3d4288fcf80182fc36db2946706dad5059ade4674341081ea63cd695aed3afcf51d66d01b5e61623d4fce329dc33835317f300dd58a9624153d0f8a25518c946046de3d55fb45a09396f4c8816c7f359a1999e32a4eba8d25920002f0bbf2e3b9850cd67f90fc11d1e3da7a9abf920d4007a952b77a9c9c1ac449abbdb1cd35ff17ef9182ed94b50e5b60c6400735362dfc37b59d23606e265aba4e88d617daff717c07b15d63c59e7e72aa19fe6f360ba4cae860c9045ad03dc845edaf2786583fb53bcdf05d21b336d25901204d7794cd3b7dddc30d28b5ac4563be1a6515d323d821ae873d0b6e5ff48dec06d8f9585ed64f0bcca2a353b64c7dcf0d6ae9084529a30db3a40163bf8acac48251c7f82b5ade896d66f15ed82850bb86689746b0144561a25634a8b2f5f62470990d4a67e105183d208ccfdb9ed024c52ffe5f0afd3219022e95d10289de8a31ce0666f8ab7ee89583ca70109d7bc4fde5922bbc35c31691d4874e0a3c9c2b9f3731029fb14c6533b650a31242a3b33002c01a2add52c76d828acfecb87193e28ea8fcc99f2cc2d51c7f512ace14f864749f20fa8c554db03c2d8fd1cb5a2274ec97a470e18783d2ba66165798d0b1c0652615e5b5cf9941474a66dda526c474c7c8d2189058db7f1cb6cc3687e5c6fe322aa8a615cefbf6abdf0a0c36cbb32a0a58183c460a692e2e89a21fa709aa3da00270c6e7368b1a0178459c96c2c539074a72f7d1867a6aa8d9f545cd270930bb05c99a8c394357b0377eb66f90529882093cb5cd5b8ad08f538966fab56c5a29883214009c76d69de18aabbbc4f5cb757e8b5422d5d7869e91e3850ddbec01bc40ed11b2134d40d109508d812e7b7be26278c585a1703e935737ae3bff4ebf9bfa383ebba7e2f7d0fb9f4b78479a70c6a6d1c0394919fd1cda8600fd284418d6f4d3cae2b213f4078df0de5a860a23738fd7f85450f3d7f9903b306f863c7808296419c06a4a12a6149a0b699719aa762ba72f0a052e971b58ac97185ec95a5b8784b60355f163c4dbea0b1fea3e8e5f23eef6abbfc155846052f396d5d97731678e48ad0668391935a6594fabd5b33440b647f343601e909a3926719bae73df1cd6af5904bce016a4934b27b01b45288ab1c13a3d72531ad31adc304e7d38291b35e2f8c3cfc153127d5465a8b953a3af7f7e5cdc22174919e50d7c195cf5a7463facc8f17baf75118259bbf5316369bd70c7211a240def65fa94dfb58f3984985b9815e32c3591c93cc9fc47e75ebac8aa0044681e34791a1b847068386520e36bdba90735c870a3cc9fc8b7be1c084d4200c5f02b7476cc7c406e1b8335c4b3e05a98f6567a942a0dddf9d0c4e26a700454b34a6f174c776978dbb7c18c40070ab899752040fa824ccf63d31f15f7f86c44905e4898f0ed731becc9d20b9b35b92a57de9f5e42c38842ae6c7d94c8b246825f8d722db09b138db117d112968ebd1ff4bb835bff94cfed81fe6f22915d2e0ce4bd1cd743788ac146fe4aa7e2ed023f88e8f96715c97548bbaf0549f1e38fc16ca351206745e7ebb59649e9e534c1633289f8cb0071bbdee509cb131bcc7f26d3b548c17fd413a3a3101583b18f3335e0380098a3cfba480f7e0ff0b606c03338790d6d2e5b2307edfc311721f1587ca55501f4b4b5aeab9773ef78f27c40e8a42bcb57c887f99a6d56be4647f12a52367936bf3b63bea50319990cb58436a5dfb819c09c27299e778a68347f40ef386c6ae97e25f9fdfb7da6b8c6efd04ec9eb83e6cf431b2661a29f4203b286d4dfd860aed5eb5456b8e4a5b9cba46fdfa83aea1e043b3182784c8cef3feeee0343be2ff4d5cfae8c202049a53a20b35fdc1c82e7b246ad7cc7e0a2b05368d873d948284a206d12ff366456ecb1123a121c8d2eaa53a423aa6b4e4c36257b7a18d1ebdb28c0f5a76a3938cbff7b0e1b43dc5237a3fa7b6266bcfba4ee44d7ca17a84e0a97d8f4baf6b9843af217d5275e07336413a3a0790856b8a25c67f6d2822dd85120dc18d70d6ffa1501b3880d036876322c1769f08bb767e9c6a7948e9e8d87ba0fad66ed655973ce1bccb8dedd9c7f2c80250769e247ce679126cb3f2fe64ae05110691ea91626d8ea26f4cf674626e62850e4523ebbfef5a926c90d9d33fa67f6bc50d35737801604e5f5b119e08c306ba7b0c09f79f871e10b2261cd8f489ccc14bc17ace710a407e0ae21732192ab6febcf4d58c53ca415f0d53e4746267874ee026106209cf1ca11099ef5e59122f4cf17d50131d0197d3b7a1fbde22d3d40635b106b27315e033e2d8e8a0cd45ba504848b470cfb1fc78d47f65226cf0968aa51fd62568b9108adffcc25193d747e735dd5e06766ee213f5ae9032ddb28cfcef714ade717c9d18b7d63e4fc057ef88fcc0894a23d36f2aa16dd530086239279cdbe14764656bc51f78f4d448c38320e32e110bbe4e90bbcf11d924563469001ea8561f5710352f44619ca1c2f108d021f520008b542071ca87c936bbd87cf42c3a06e10976cd82e074974601ad86662b283ef5d2fd63486a98acc91758160a5e008333ad3b365be36836a196643b4136fbec90ef50bb944cb17ee0b55adc5a60dd81809e74d3f4ab5751a4c1b94fe7082f86c6935b867d15bc27328c3a7d9e5215fc8a2fc7f3d088446353ec9c92d3b5d01fa372540d1de064ea02030a300eaf73eb4eb40e5b2ec2b0c6d3d52f63369bdcc63d268a065e18aeee15474393c08eebfcb9d2a795e5422fd50fd099f85759966ba28127bf5b1eae0851b5c567c23ac33469791cbf78e827f98c4269b997008ac745188aa2a77cddd83574858a7a321f46cb0db5b89b100318c818500dd4d5a8aaf16c38bf32831099cac8b121e191ea8c50573f395bc70753839643e602b3b2242eaba726ec243a643392df202c6fde7e8436609969436aa1707fee35a08e0aafdfcd6471db08b9814e4547689f04e5f8b918fc0a8fd82784865ef5cbcc53da7e2fb1adc45e5a429833003b159edd94f3e1400b784181c81a270517c22fcaa0fd7286adafe160b3b17495ca6186e7e15c878be4c228cb5f79a4d940dbdfaf94392aec9aaa252c9eb0b58dded996e081fc1bad2a7a229f715b4690d8871ae7b086961f7b7d44e1f9a2bd093042919d0543007e29e222c057540f0ead016575771f85811d93583af887ca5f8094c9274b4b933f528788661c9eac7d6f736024051df17028b8d06f4ca6d33dcef7fcb6cb4a063b764706fd0d457c6119b6ce77fe47d40881bbc41d5fc042717fe4b599132af01cdb6032fcec422410c071f3d83eae54264ac430927e85a468308f96dfa26ede5fa047df6d63fadfd3861bd3507ae199274d6e0b3e329a10a58cef6535747ee4a6c5ca9ec10a39f2acff29a33b82d09b899d6c4c1271ac8e6721c0c77dbb6af1b4b4cb7fca8dfb716a76f6f587950d2ae419c4bfcdfbfe4fc08605627964b126c39ded0e22260c7450b7ae8e9397a27ad0f614577524224eed1976a085dbc1889d2495ce1b94a32153d9e433b27beecbd7e87a411248aeadb5c6d155148336bb55f23bfec0efc2d32463b46c2293206137ded47fe3c1cc7f64e135222308209640dadff7c9da43f9939894b7a67c298d7a790a5ec56391076f8c9518d85aa1d5df44cf3043c15ceaf489e6b7eeaad05907373c4fd7a16a4982299b66791d3436ddbdf438bfd98e2d94f0d41835c604b992d69249d798fc66ff358905dc801c79d60ae1a498898a7faded0502cbb751bb56ec28ce4069b4531c7c20c7dcdba2b0f21691bc776d7eb4295124f8411832f8941229c43b0881aee44425f6eb418143ed19d1fe79fe55cb5744259a4bc13c3512227c06a8c42563c9951516327ea8e90b9f4313e146e8b452814a93fac4564ea1bcd51360c8d19bbc07331ee161bff595e330397dfa532b2b2d25a428a999bf9b357335196ad4a7d7d2db12ca056549223039379aaaf5f89d281e04e986f5dba96ecaee589032db3d66118e4ce169a6a3034394baec899bc5eab4385973728be47fbdaba1d6cf6db50d77d394306727244eca23f2b68af3e38d275799bc81c840fd425e06d516cc33ca100c0d704ba1606ef4199d1b47d9a756a171309746ba0cdf48e9a0ee457cfe19a99d4112405d3318968ca97e13f72f271df0a5b487b3c5869fdddc6d53c1e7190ebcccad22f5d52bb99780a1887ac2fa0b933a0ca708ab7f20e1bb46ec6238351ecfee46cb42bb574270b46f4a3626ba8af5b5b3c96ccb7f1acd772b13277412fdd4ea740f8c6ea0d2383377115f8d17c095b8325ffc82ce966150413de37d622bc426c3f8ceb1cde12069e3c41e90d248ac627be702482c4efb2f028e2b2a607e2bbff190ddb710d7e36a7811621baab0f134434c254cbef59e86af197b6289e72d24714ca1ea3784bacb250676a778bf9d6ce2549799af999b917c8df2db58ec799ad51f10d0bd3707aa5f3c3aca8b8a105914825e6b78709eed6190de883b34bfe6f4bd0c91001a5a5d168a5212c95ec4ba15c700c937fd359e401899e56e3db259da628943951e8b2a366c94ec46b9f6b5d4da72943ba738d662d2cdb4fef6091ead96cc74d272c4c89077765ab6e93cafc737c82ab30b13b40d14c595d7a5efe4e89cccfb81275776c2b8df49db7c37f8a149a1a53703a255095021c125679d6929d8b46de63254204b79f43bef2f2bd7f0e2143de50616e19346239acb7db9a980baf1f212d2c26c69fae7d759c46da0aa97f443031d06f8b6a85794ec9fc778d30f08a4292a5e13488767741ff120121e0037c3830d32b6181008b47a8d48126af48719a7e7396ca1d6e787fba426a54410364baf076426f4c72dbddf964e5dc617bebfe8d381320150ec065cdd87288245115a18ded71c70b06cc02bdae6d695cbbb5b3d8a2aa16cdf80d84d511ac1b754f472f66ea6c5e312b4c67a66067e1f9d32de4d1d14c4c4e2cab3f40c2895c18a56b94fa40b75641723e7c147a594c89511956f046f0fbd26f3d3814c13ab717c7e164bdc9f8c0e5ca120724989897db7def83513e8325176d04a774021ba934b174af4b063e8764a8cf7c81822f8eb2c5870ad4b876051fe5c18c352cc03b885f74c65d22a5f9eb0fa399782ad33639c0ade4a2c1ff3ceab622373b98410f25c3de2d570f847fcb8492ba5b06661287a4e09af59374ccd9d080fcbce8ece50bc61c96d3b5ecfada0a974f04329d6f245083c3e7d49e7c59e2cc437de2add8bde7518f0b8961c7565705cafa86ff93a9f3fe8d22a7f76446e4e26a7534f8714081433b4f5c95d68a1cd7bf0e5cd74adfadc851287f9ac437cf0c67d3c5e7bfd49fb44f4277b860d657035303cb2d872fe8530e406d3607e3e33b45f47a8a42a229362cb0208cd5de79a7c0069b7fa8263c606b2f80b66d7562d975b9f096fe599cd28ba85521cd123f665d6c101665af1d4f6c850e28b3ee8b8f74d2c63e7331a55edea8024059810071122e0f8ec7c3776a148a28a987e2db7eef4f493c4e69e20f2ce2caeb305a23bede1aff4bcd706f87be91340d48eee4f8ea2fa7f496e882ee68c9f60daac3ef08c95452d936a8762d15a47659e4a791b03ab52cd0407cbe3677b4cb3b9c2d3f19b8f21250b28abfe1eb6c4e4bc92014fc4f10b165a594c30131f571aceb009e5574219584e2fd3f3281bd6156697e8347bffb50c3b699807bff24fabf9a7ced1d796078dce628d3ae6445b81c8fb6a633b9f25dd4d25a5a6d64b8af3c71c5b392822aa9e5748f3ce90b0c44f7857ec8dbe90d15c9b31152430b245139da98c63cf1efb6d89c674b15e51d30a282f779a6dc4b23a5e546fcf8cb0bdabaf6640651b98b6e8c7afc5c084938ef0d099f87466cd1648cb9aff11054c70ebd8921e459d6245b89ea05cc218d48c331e3138a7613a1500dbdc8b5077e9063b39a4a6aa8971e910228f026d3437b1344dc8f746bcc34a94605fa855200afc964565df617bd3c04d4998c162623cc4975fdea827256f8f61da092fef0e4a3023a03c6aa606579111dc80c118a470b9a690409b125cee61d64472d40eec1c222cffe7c3a59f8a00fe2fe51b072644af0be728bbf948f2848d1371b34d09f0fcf3fcc31d084ad69d7edc2e1aff6651f7f0123e1a83c44891567a34357b114e060e82464d18cb73a2e7e2b5f604c09938eb06df26a0141a55e7fc84f219c7728b022ecba2f1c71266a5e6aa7bd784a8c6e0db32b53cc03aa500fff71b06855acf22b8335531655fa414693b3fe9a320a98781ca9f60b955b3817f54873915ad3fcc843b172a4cbc5d3091dc4b301b4417a391b66895ee37ab81a6fe186fcf6ee7f61fe3b89556edda3130153e2562aa190be6994ef738fab5c2dda559e63f4b5b1f08faecf5e3cd9afc5d6336c45273ad5f93dd26d0894e2dc587f7fc1b26ea6b2428e55f07d9e175fdf9d9e0b58df7e169079cf203f21e5aafcd3a7710a0259d87be594ba30bcb2a6a2e26b28f499c3145889198e5aef16fafdbd1c440c300d83100d11d0a0647f0066608e847b6b109e9853b2549ffae9498ab5042823f0fe0ab248ca6ef9de115ecec752dcd1bf2e4e55e79cc0d17866c97ddff73f7e35eb598e60ecc8ac4cab0db57c948aca8750b1543bc926d2cd7a6239a683cba85400d0bcad56e943a4f614bea94990bc426e1eae75046b6baed05a59bf0084eb777d824d0d212e9819e2ea7db881c44fbb85bc374a0d6235f8392a3d9a761a5747d75d96cdc3c8dd7272eade200d57230d15e762228da98178a193d7d95284b20e82d74228146fdf68d59b37c5e7f78c0e14e7c40bd4f4d9cf0b189b69983dd39e29aa6439ecab0a5b294d2a1216ce31cac6d1b2358d2b0476c4d8002519b6d63639b2d4564e2458c8e06bdeebe82262570777780f43b110a96547415a69a38ef0ece0c2af16b9cf11ff8326e2de6dd0333b2ede445aa3a1057824478bfc71fd00dee601938734810d816f4dadd35f4c130598b9678682552d0d9bbf0116e52f71e30f449c6e70b673af7186d562e4591cfb9fcc9c591cfa471b8e3ea987e8e6b5f57d6ea8dd522e74d63169f343b20f9816236320cb16a04fc7b629e6240bc1686651f69bf37db30dde39875d57beccdc24c9d5575b0bb0b86f6d2e06f857152874f3a9034cb6018c5f83c55665f22a4195cb93fde9d0294d0769969423c54cdea07300e6f2bcda80f8e35f2631ceddbe3d29cfbb81a94d60b576e5c471ae1dacac226e9178369177bae4f33fec7b710b587ce317d3781e5fa8bae55167b7b93cdd061782786fe574fb7296b7c338edcd16642149ef44e694f8d30eb602193457a9956acb38b8ffdbf22b7bd93bda15b79cf2ed4c8e4606052696fbf38a852bef0ef9e8cecc8faa42493ff945a0b6cf235f7a64b03e4cf567ffe3687b6208c42c7df3272008f9c57ef92801444faf4932120223aa8882a57ed3cd8fdce71fe4ac4ea41dec00b74c0310d25260e0f95a4b89b5cd96ae446b33bc433181db39d0b4e48de172186f9c50ef7ac72adaebb2202b358a1250070349c66516d7f5d895ecf2dec601759abe52e2c7fec904db0b8a4390a4f8367db536a6a1eedc4435a6de58b62b3d4a946061b77adc10d21535a026657ec07ce19d9e097f93da31ef963ec7cfb971edaa8acea7537f5280b51188d88de355a79408f5c1fac07234ef9629ee992abfc874b33572362b95722ff1714cc238c68be7850c3bfa7bb5bf2c41122192cea2783f79cb558a65198c93a6009fd3102ed3d7cf677c5c632ec1a31abc087e2ab717c9abd04caf709a3855ddbfb70a81099f22ec5f49f3122e6633882f813bb76e2597670e37f36240e00a75b4b90a132cf2b4a652269ab8be1697087fa262593a16639f496edb72b0c906eee57a219c51dd548a697295bfac80d400d834c486a7642aab0d12aa4617abf1f604b5d6c9cf40c57fc8454761ba7fe54cebd8ec43daa495a6feba2e7524b6b771348100b3af4eb145642d006c3acf26262f8de8a6465f4eef60bea55615c19c50790daa8a0a39d42d66f89e4e6e3a5029cda85b50bb256ce3c57ee6aed2ae47db1d10b05bea586992a0b3a282d36d7c8d254badfa4a8b7f91d0fef5bc971b99b7c2d0aaf904a42b11139cc22d6450b6467c9453f1392193fd16b9aa565c757fa9457a9723fbfc6ce3b2f8381f0393b4eb984068adb273a50ccbe4e8fb708902179e0b8d645481a7f3919e07f758cfd12a3496bdd5b063d99ef127cb36dffefc4a29c23e63da9f4ab05a20faf7d73d70c619d48a92c653d415b7a9aca0c499937fd2acc6b1e6842d5f15c00bfa3b1d1c1655f8601c13f94291bcf76979b2c45d30384e4ce99a60ec088c9328a393581a8bf247609e5f9f025d98df1ed6c25ed4d6dfc67c98ec93b9158e7ccb8e8a50f4548479444ca7386ae077140d8a26459123dc28c9bcd531e3287f74cea298cd4f475c45e51792e439ba4368171a5ff60656c1ec132ce5affd6814f5f0fd786b15479a8bd2d2d3874bae96ab58e3b603bb251746b67bd00bb210f3d00e3725ad2a9441a11c8d320aa18e83383815f1eae1a7f195034f9dfe7ff7c4fd84acb7c2e22ec131d928e425cf96b64b562de90593cd61f237c11e2a4fc33a7f5333e1c6085a8f0d393e346646f36b3c4767c3681ce53c75414d72c57121fb10ac3f0eb8b784794cf2dcafcf0fe0c7b003d6171c20a3d63b44d168ef4bb79da894b5555c6f69a4d6e82fa558526e1bb75c63dc8e0fcbe3b9d462c0933eec9f034d4e917f30d48e98a93755c7c8771648711b81e5cb6f4e30680b7ce662cee5c8a02df4d1cc8f6aef8e632eaa09474321f231b7ed4cc9ba2a993693f4169b7752402bea7309d0412c9269799914894ebfaa9785716406225a18101a6f393dad47dc052c45bcad6f8bad49f108d6d179588d1c08db51ec9a50ce2702c9ecc1f9ad68633060579801e2d131d1044effa20ac6fe815f15d64e900c7d72d57ce8a398ac34119490d71b1058ffc111e089617145d592119352203f341c0ba91941455c29d5c253bd219bfed0d556212098a969a38b6d561be89635273ae7e4531210dd7b0d0310f2806a6e7a46c9f908c19862f9e05206d8408b246f4b8a508b9e78824cb9da63e4b6fcc2bdc9c391f2d4b9e3008dba425a937e025130b7cdd946dafe43e3a18f7331c04e063df4ee19cdd09e2c652acf3f4ced146b3b38f0fb8f8dae0f9fb1f87881cb1e7cbe6c33da4b704f03921810fbf3368a11c3014d2a4bfca1396ed43b3c3a3c6de41ee3740d40eb28983b2967f74a5a2a0515f68f70f4746dc94f29607f14b671c088df491386a38cc6f9765cc9b2ac7e91d80a2506624a9b0864aea397eddf2a9647d6f42cbdc68f4e8667f3d5614faf151b94acde040329ebcacd4d6ad474306c990998423ad8fb307e4a47e4e73463d913c812e3316a77bf238b89f69178dc0924253c110ca5396095d7c1689526e1cbf8dadb924f19df73aa7c97b59e013d6c4ddc687e06e10f82c7aeb21011e931222a777ab3a87759cb893b380ce15a22491ef3dacf62512e3d0561a137aa294d981601813767e44decfff7e84b4c33d6d73022f20faea96ce49976f75c85b390bfdd508a8c2a1f77681add20cfb715fffef359dda3e824d607ae19f298d7323210b7bd3fa6db1bdbdf613d13b6b7ef349278eabd1ec4ae836ad0307e3f5956e753b39c5edb973a6f90012962e3bb75f673461c211e711109320152825f5c9fe4b516f85eb0ba33e8719843f1ca4c965bacdf870dcd53dc05ea444696c615be7cb9214235f008b4c458fd0cff1b313e3433eed9ac1495785a57c4da01fded6650a61d29cecd2462a84faea9b689d050021f4b7d883edb39ad74a5eeec5a898f73f40fff5b74948fbf96ad6afd14d48a2f4b15782d163f219b069f2da414905b5b97576f4486fea35e93d2aaa4b41afeff1db600782acd9658479c960603aaaccf3fdb10bbe916936ca4526e2a3751ecef7abe2500bf18512d52006bc80c2fe5481727125e0a27d4342f3046e626b753b40eb210dbd64c8f67059fbe0c93146d09f30550cd33f3d03986f842a9421f07fc94f09ca898526e4cd51ba9b268beffeaa5f381c59964b5ca8b04918433b9229080b54be25920c8c3ddfa2b98d5c095a6800c1d3d03c8b30e989198fc96c3c8dae0d8d2ca09365d23c9e46abb40591d30817eb8e33985dedd0387b3ddc66fb655d37e41efbad4c05af86ce280afa66e591a619bf9236e5b7b7b31bdc87f63257aa652630afbe9ad8363750c04042c43ad5f392076f7481b3ca6b3dd83d7e87c604f8b08b0f13234fe8d8e5ab60756ae91d0d69eb144a3db813dd6095bcbee564b04a713152e40cf86285c1d51088832d18184b90f8db1d7e7d55bc79a2178b833523e0af31c027172271477162fc13d848d082b37bd1fc5700383cbb36ccc550ee3ec492266f9a86075bb32171abab9a335317d47a85de18d44809c6fbdbe76d2e5a5aec7cf00250eb24f453038b89e6cddb09e646676419c252e14f0d661f85747cc17f67732ca487012c3bb8ca822a9518695e68620af1ee12d2c6e48e0775128992922364c7bef20448e44025d399918109fc3ecc93f1c57c04be4409df78823aa4f098e3883282d7f9cbdac7aaa49dc8795c67578c862a0e45097499bbdf0b0e37");
//        FixedSecureRandom fixedRandom = new FixedSecureRandom(fixedRandomBytes);
//
//        // Receiver side
//        KeyPairGenerator g = KeyPairGenerator.getInstance("NTRU");
//        g.initialize(NTRUParameterSpec.sntrup653, fixedRandom);
//        KeyPair kp = g.generateKeyPair();
//        NTRUKey pkR = (NTRUKey)kp.getPublic();
//
//        // Sender side
//        KEM kemS = KEM.getInstance("NTRU");
//        KTSParameterSpec ktsSpec = null;
//        KEM.Encapsulator e = kemS.newEncapsulator((PublicKey)pkR, ktsSpec, fixedRandom);
//        KEM.Encapsulated enc = e.encapsulate();
//        SecretKey secS = enc.key();
//        byte[] em = enc.encapsulation();
//        byte[] params = enc.params();
//
//        assertTrue(Arrays.areEqual(em, ct));
//        assertTrue(Arrays.areEqual(enc.key().getEncoded(), ss));
//
//        // Receiver side
//        KEM kemR = KEM.getInstance("NTRU");
//        KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec);
//        SecretKey secR = d.decapsulate(em);
//
//        // secS and secR will be identical
//        assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
//        assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
//
//    }
    public void testKEM()
            throws Exception
    {
        // Receiver side
        KeyPairGenerator g = KeyPairGenerator.getInstance("NTRU", "BCPQC");

        g.initialize(NTRUParameterSpec.ntruhrss701, new SecureRandom());

        KeyPair kp = g.generateKeyPair();
        PublicKey pkR = kp.getPublic();

        // Sender side
        KEM kemS = KEM.getInstance("NTRU");
        KTSParameterSpec ktsSpec = null;
        KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, null);
        KEM.Encapsulated enc = e.encapsulate();
        SecretKey secS = enc.key();
        byte[] em = enc.encapsulation();
        byte[] params = enc.params();

        // Receiver side
        KEM kemR = KEM.getInstance("NTRU");
//        AlgorithmParameters algParams = AlgorithmParameters.getInstance("NTRU");
//        algParams.init(params);
//        NTRUParameterSpec specR = algParams.getParameterSpec(NTRUParameterSpec.class);
        KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec);
        SecretKey secR = d.decapsulate(em);

        // secS and secR will be identical
        assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
        assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
    }

    public void testBasicKEMAES()
            throws Exception
    {
        if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
        {
            Security.addProvider(new BouncyCastlePQCProvider());
        }
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BC");
        kpg.initialize(NTRUParameterSpec.ntruhps2048509, new SecureRandom());

        performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
        performKEM(kpg.generateKeyPair(),0, 16, "AES", new KEMParameterSpec("AES"));
        performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));

        try
        {
            performKEM(kpg.generateKeyPair(),0, 16, "AES-KWP", new KEMParameterSpec("AES"));
            fail();
        }
        catch (Exception ex)
        {
        }

        kpg.initialize(NTRUParameterSpec.ntruhps4096821, new SecureRandom());
        performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));



    }

    public void testBasicKEMCamellia()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BCPQC");
        kpg.initialize(NTRUParameterSpec.ntruhps2048509, new SecureRandom());

        performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia", 256).build());
        performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia-KWP", 256).build());
    }

    public void testBasicKEMSEED()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BCPQC");
        kpg.initialize(NTRUParameterSpec.ntruhps2048509, new SecureRandom());

        performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("SEED", 128).build());
    }

    public void testBasicKEMARIA()
            throws Exception
    {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BCPQC");
        kpg.initialize(NTRUParameterSpec.ntruhps2048677, new SecureRandom());

        performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA"));
        performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA-KWP"));
    }

    private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParameterSpec ktsParameterSpec)
            throws Exception
    {
        PublicKey pkR = kp.getPublic();

        // Sender side
        KEM kemS = KEM.getInstance("NTRU");
        KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
        KEM.Encapsulated enc = e.encapsulate(from, to, algorithm);
        SecretKey secS = enc.key();
        byte[] em = enc.encapsulation();

        // Receiver side
        KEM kemR = KEM.getInstance("NTRU");
        KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
        SecretKey secR = d.decapsulate(em, from, to, algorithm);

        // secS and secR will be identical
        assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
        assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
    }

    private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec)
            throws Exception
    {
        PublicKey pkR = kp.getPublic();

        // Sender side
        KEM kemS = KEM.getInstance("NTRU");
        KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
        KEM.Encapsulated enc = e.encapsulate();
        SecretKey secS = enc.key();
        byte[] em = enc.encapsulation();

        // Receiver side
        KEM kemR = KEM.getInstance("NTRU");
//        KTSParameterSpec RktsParameterSpec = new KTSParameterSpec.Builder(
//                ktsParameterSpec.getKeyAlgorithmName(),
//                enc.key().getEncoded().length
//        ).withParameterSpec(ktsParameterSpec).build();
        KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
        SecretKey secR = d.decapsulate(em);

        // secS and secR will be identical
        assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
        assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
    }
}
